package com.zhou.code;

import com.zhou.code.model.FileInfo;
import com.zhou.code.model.TempConfig;
import com.zhou.code.template.DataModel;
import com.zhou.code.template.Node;
import com.zhou.code.template.NodeType;
import com.zhou.code.template.TemplateUtil;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public abstract class CodeFactory {

    abstract Reader getReader() throws Exception;

    void start() throws Exception {
        //清空旧的文件夹
        cleanDir();
        //初始化模板配置
        TempConfigFactory.init();
        //获取数据源读取器
        Reader reader = getReader();
        //获取数据库表的配置
        List<String> targetNames = TempConfigFactory.getTempConfig().getTableNames();
        for (String targetName : targetNames) {
            DataModel dataModel = reader.read(targetName);
            dataModel.context = TempConfigFactory.getTempConfig().getContextValue();
            work(dataModel);
        }

    }

    void work(DataModel dataModel) throws Exception {
        String targetName = dataModel.targetName;
        List<String> excludeFields = TempConfigFactory.getTempConfig().getExcludeFields();
        dataModel.columns = dataModel.columns.stream()
                .filter(column -> !excludeFields.contains(column.columnName))
                .collect(Collectors.toList());
        TempConfig tempConfig = TempConfigFactory.getTempConfig();
        List<FileInfo> fileInfos = tempConfig.getFiles();
        for (FileInfo fileInfo : fileInfos) {
            String template = tempConfig.getFileRoot() + fileInfo.getAddress();
            Node node = TemplateUtil.getTemplate(template);
            //生成文件信息
            String fileContent = buildFileString(node, dataModel, "");
            String targetFileName = TemplateUtil.getTemplateFileName(targetName, fileInfo.getFileSuffix(), fileInfo.getFileType());
            //文件输出
            mkFile(targetFileName, fileContent);
        }
    }

    private String buildFileString(Node node, Object data, String content) throws Exception{
        if (node.nodeType == NodeType.STRING) {
            return node.content;
        } else if (node.nodeType == NodeType.ATTRIBUTE) {
            return ColumnUtil.formartHumpParam(ParamUtil.getParam(data, node.param.paramName).toString(), node.param.columnRule);
        } else if (node.nodeType == NodeType.PARENT) {
            StringBuilder childContent = new StringBuilder();
            for(Node child : node.child) {
                childContent.append(buildFileString(child, data, content));
            }
            return childContent.toString();
        } else if (node.nodeType == NodeType.FOR) {
            StringBuilder childContent = new StringBuilder();
            Object forList = ParamUtil.getParam(data, node.param.paramName);
            if (forList instanceof Collection) {
                for (Object forData : (Collection) forList) {
                    for(Node child : node.child) {
                        childContent.append(buildFileString(child, forData, content));
                    }
                }
            } else {
                throw new RuntimeException("for循环表中标注的成员属性【" + node.param.paramName + "】不是集合类型");
            }
            return childContent.toString();
        } else {
            throw new RuntimeException("非法的节点类型：" + node.nodeType);
        }
    }

    /**
     * 获取生成的文件的细分文件夹路径
     */
    abstract String getTargetFileDir();

    /**
     * 创建一个文件，并将fileContent中的内容写入进去
     * @param fileName 文件名称
     * @param fileContent 内容的字符串
     */
    public void mkFile(String fileName, String fileContent) throws IOException {
        try (FileWriter file = new FileWriter(Constant.TARGET_DIR + getTargetFileDir() + fileName)) {
            char[] chars = fileContent.toCharArray();
            for (int i = 0 ; i < chars.length ; i += 100 ) {
                if (i + 100 >= chars.length) {
                    file.write(Arrays.copyOfRange(chars, i, chars.length));
                } else {
                    file.write(Arrays.copyOfRange(chars, i, i + 100));
                }
            }
        }
    }

    /**
     * 清空旧的文件夹，然后创建一个新的
     */
    public void cleanDir() {
        deleteDir(Constant.TARGET_DIR + getTargetFileDir());
        File file = new File(Constant.TARGET_DIR + getTargetFileDir());
        if (!file.mkdirs()) {
            throw new RuntimeException("创建文件夹失败");
        }
    }

    private void deleteDir(String path) {
        try {
            deleteAllFile(path); //删除完里面所有内容
            File myFilePath = new File(path);
            myFilePath.delete(); //删除空文件夹
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将文件夹中的所有文件都清空
     * @param path
     * @return
     */
    private boolean deleteAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
            return flag;
        }
        if (!file.isDirectory()) {
            return flag;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                deleteAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
                deleteDir(path + "/" + tempList[i]);//再删除空文件夹
                flag = true;
            }
        }
        return flag;
    }
}

